import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Collapse, Form, Row, Col, Tooltip, Icon } from 'antd';
const Panel = Collapse.Panel;
const FormItem = Form.Item;

import _ from 'lodash';

import { renderField } from './formFieldComponentRegstry';
import FormWrap from '../../../components/form/FormWrap';
import './Form.global.css';

class DynamicForm extends Component {
    static propTypes = {
        onValueChange: PropTypes.func,
        handleValuesChange: PropTypes.func,
        handleFieldsChange: PropTypes.func,
        handleAddonAfterClick: PropTypes.func,
        layout: PropTypes.object,
        size: PropTypes.string,
        initData: PropTypes.object,
        formModel: PropTypes.object,
        showArrow: PropTypes.bool,
        className: PropTypes.string,
        renderItems: PropTypes.func,
        bordered: PropTypes.bool,
        accordion: PropTypes.bool,
        handleValidate: PropTypes.func,
        emptyText: PropTypes.string,
        handleFormReady: PropTypes.func
    }
    handleValuesChange = async (props, changedValues) => {
        const { handleValuesChange=()=>{} } = this.props;
        handleValuesChange(props, changedValues);
        /*
        // 暂时不这样进行验证
        await handleValuesChange(props, changedValues);
        if (this.form && Object.keys(changedValues).length) {
            const name = Object.keys(changedValues)[0];
            const errs = this.form.getFieldsError();
            const names = name.split(".");
            let tmp = errs;
            names.forEach(n => {
                tmp = tmp[n];
            });
            if (typeof tmp === 'undefined') {
                this.form.validateFields([name], { foce:true });
            }
        }
        */
    }
    handleFieldsChange = (props, fields) => {
        const { handleFieldsChange=()=>{} } = this.props;
        return handleFieldsChange(props, fields);
    }
    handleAddonAfterClick = ({ form, field, fieldName, fieldValue, fieldSet, domEvent }) => {
        const { handleAddonAfterClick=()=>{} } = this.props;
        return handleAddonAfterClick({ form, field, fieldName, fieldValue, fieldSet, domEvent });
    }
    mapRules = (field) => {
        let { validateRules=[] } = field;
        if (typeof validateRules === 'string') {
            try {
                validateRules = JSON.parse(validateRules);
            } catch (e) {
                //ignore
            }
        }
        return validateRules.map(r => {
            const copyR = {...r};
            if (copyR.pattern) {
                copyR.pattern = new RegExp(copyR.pattern);
            }
            const len = _.parseInt(copyR.len);
            if (len <= 0 || Number.isNaN(len)) {
                delete copyR.len;
                copyR.min = _.parseInt(copyR.min);
                copyR.max = _.parseInt(copyR.max);
            } else {
                copyR.len = len;
                delete copyR.min;
                delete copyR.max;
            }
            copyR.required = `${copyR.required}` === 'true';
            copyR.whitespace = `${copyR.whitespace}` === 'true';
            return copyR;
        });
    }
    getLayout = (formModel, fieldSet, field) => {
        const { layout:forceLayout={} } = this.props;
        if (!_.isEmpty(forceLayout.labelCol) || !_.isEmpty(forceLayout.wrapperCol)) {
            return { labelCol: forceLayout.labelCol, wrapperCol: forceLayout.wrapperCol };
        }
        const { layout:formLayout={} } = formModel;
        const { labelCol:formLabelCol={}, wrapperCol:formWrpperCol={} } = formLayout;

        const layoutType = this.getLayoutType(formModel);
        if (layoutType == 'horizontal') {
            if (field.layout && field.layout.force) {
                return field.layout;
            }
            if (!_.isEmpty(formLabelCol) || !_.isEmpty(formWrpperCol)) {
                if (formLabelCol.span > 0 || formLabelCol.offset > 0 || formWrpperCol.span > 0 || formWrpperCol.offset > 0) {
                    return { labelCol: formLabelCol, wrapperCol: formWrpperCol };
                }
            }
            return { labelCol: { span:8 }, wrapperCol: { span:16 } };
        }

        if (layoutType == 'vertical') {
            return {};
        }
        const { layout:fieldLayout={} } = field;
        const { labelCol:fieldLabelCol={}, wrapperCol:fieldWrpperCol={} } = fieldLayout;
        if (!_.isEmpty(fieldLabelCol) || !_.isEmpty(fieldWrpperCol)) {
            if (fieldLabelCol.span > 0 || fieldLabelCol.offset > 0 || fieldWrpperCol.span > 0 || fieldWrpperCol.offset > 0) {
                return { labelCol: fieldLabelCol, wrapperCol: fieldWrpperCol };
            }
        }
        const { layout:fieldSetLayout={} } = fieldSet;
        const { labelCol:fieldSetLabelCol={}, wrapperCol:fieldSetWrpperCol={} } = fieldSetLayout;
        if (!_.isEmpty(fieldSetLabelCol) || !_.isEmpty(fieldSetWrpperCol)) {
            if (fieldSetLabelCol.span > 0 || fieldSetLabelCol.offset > 0 || fieldSetWrpperCol.span > 0 || fieldSetWrpperCol.offset > 0) {
                return { labelCol: fieldSetLabelCol, wrapperCol: fieldSetWrpperCol };
            }
        }

        if (!_.isEmpty(formLabelCol) || !_.isEmpty(formWrpperCol)) {
            if (formLabelCol.span > 0 || formLabelCol.offset > 0 || formWrpperCol.span > 0 || formWrpperCol.offset > 0) {
                return { labelCol: formLabelCol, wrapperCol: formWrpperCol };
            }
        }

        return {};
    }
    getLayoutType = (formModel) => {
        const { layout:forceLayout } = this.props;
        if (forceLayout) {
            return forceLayout.type;
        }

        const { layout={} } = formModel;
        const { type } = layout;
        return type;
    }
    renderLabel = (formModel, fieldSet, field) => {
        return field.label;
    }
    getLabelProps = (formModel, fieldSet, field) => {
        let label = this.renderLabel(formModel, fieldSet, field);
        const labelProps = {label};

        let help;
        let helpTrigger;
        if (field.help && field.help.enabled) {
            let { style, trigger } = field.help;
            if (typeof style === 'string') {
                try {
                    style = JSON.parse(style);
                } catch (e) {
                    style = {};
                }
            }
            help = <span style={style}>{field.help.text}</span>;
            helpTrigger = trigger;
        }

        if (helpTrigger === 'label') {
            labelProps.label = (
                <span>
                    {label}
                    <em>
                        <Tooltip title={help}>
                            <Icon type="info-circle-o" style={{ marginRight: 4 }} />
                        </Tooltip>
                    </em>
                </span>
            );
        } else {
            labelProps.extra = help;
        }
        return labelProps;
    }
    getFieldValue = (field, values) => {
        const value = values ? values[field.name] : undefined;
        return value;
    }
    renderFormItem = ({form, fieldSet, field, getFieldDecorator}) => {
        const { size, initData, formModel, auth={} } = this.props;
        if (auth[field.name] && auth[field.name].readable === false) {
            return null;
        }
        const { layout:{labelAlign='right'}={} } = formModel;
        const layoutType = this.getLayoutType(formModel);
        let fieldName = field.name || field.id || '' + new Date().getTime();
        fieldName = `${fieldName}`;
        const initialValue =
            (typeof field.fixValue !== 'undefined') ?
                field.fixValue :
                //(this.getFieldValue(field, initData) || field.defaultValue);
                typeof this.getFieldValue(field, initData) !== 'undefined' ?
                    this.getFieldValue(field, initData) :
                    field.defaultValue

        const renderFormItem = (args) => {
            const component = args.component || args;
            const valuePropName = args.valuePropName || 'value';

            const labelProps = this.getLabelProps(formModel, fieldSet, field);
            return (
                field.visible == false ? (<div></div>) : (
                    field.hide == true ? (<div></div>) : (
                        <FormItem
                            {...this.getLayout(formModel, fieldSet, field)}
                            {...labelProps}
                            key={field.id}
                            hasFeedback={field.hasFeedback}
                            colon={ field.hideColon == true ? false : true }
                            style={{ width:"100%" }}
                            className={ `form-item-label-align-${labelAlign}` }
                        >
                            {getFieldDecorator(
                                fieldName, {
                                    initialValue,
                                    rules: this.mapRules(field),
                                    valuePropName,
                                    validateFirst: true,
                                }
                            )( component )}
                            {/* {getFieldDecorator(
                                fieldName, {
                                    initialValue,
                                    rules: this.mapRules(field),
                                    valuePropName,
                                    validateFirst: true,
                                }
                            )( component )} */}
                        </FormItem>
                    )
                )
                // <FormItem 
                //     {...this.getLayout(formModel, fieldSet, field)} 
                //     {...labelProps}
                //     key={field.id}
                //     hasFeedback={field.hasFeedback}
                //     colon={ field.hideColon == true ? false : true }
                //     style={{ width:"100%" }}
                // >
                //     {getFieldDecorator(
                //         fieldName, { 
                //             initialValue, 
                //             rules: this.mapRules(field),
                //             valuePropName,
                //             validateFirst: true,
                //         }
                //     )( component )}
                // </FormItem>
            );
        };

        const onAddonAfterClick = (e) => {
            const fieldValue = form.getFieldValue(fieldName);
            this.handleAddonAfterClick({
                form,
                fieldName,
                fieldValue,
                fieldSet,
                field,
                domEvent:e
            });
        };

        const onValueChange = (newValue) => {
            const oldValue = form.getFieldValue(fieldName);
            this.props.onValueChange && this.props.onValueChange({fieldName, newValue, oldValue});
            form.setFieldsValue({ [fieldName]: newValue });
        };

        const formItem = renderField({ form, size, field, onAddonAfterClick, onValueChange, layoutType, renderFormItem, auth });
        return formItem;
    }
    renderFieldSet = ({form, fieldSet, getFieldDecorator}) => {
        if (!fieldSet) {
            return;
        }
        const { showArrow=true, formModel } = this.props;
        let { fields=[], isDynamic=false, dynamicContent } = fieldSet;
        if (isDynamic) {
            return (
                <div
                    key={fieldSet.id}
                    header={fieldSet.label}
                    style={{
                        textAlign:"center",
                        padding:"10px",
                        background:"white",
                        border:"1px dashed gray"
                    }}>
                    { dynamicContent }
                </div>
            );
        }
        const layoutType = this.getLayoutType(formModel);
        if (layoutType == 'inline') {
            const colspanOfForm = formModel.layout && formModel.layout.colspan;
            const colspanOfFieldSet = fieldSet.layout && fieldSet.layout.colspan;
            const colspan = colspanOfFieldSet > 0 ? colspanOfFieldSet : colspanOfForm ;
            if (colspan > 0) {
                const defaultSpan = Math.floor(24/colspan);
                const rows = [];
                let cols = [];
                const wraps = [];
                let index = -1;
                fields.forEach((field, idx) => {
                    const { layout: fieldLayout = {} } = field;
                    let colspanOfField;
                    if(field.visible == false){
                        colspanOfField = 0 ;
                    }else{
                        colspanOfField = fieldLayout.colspan || 1;
                    }
                    // let colspanOfField = fieldLayout.colspan || 1;
                    const { forceSpan } =  fieldLayout;
                    let isAutoWrap = false;
                    if (colspanOfField <= 0) {
                        colspanOfField = 1;
                    } else if (colspanOfField >= colspan) {
                        colspanOfField = colspan;
                        isAutoWrap = true;
                    }
                    const isWrap = fieldLayout.wrap == true;
                    if (isWrap || isAutoWrap) {
                        wraps.push(field);
                    }
                    let isLastCol;
                    if(field.visible != false){
                        index ++;
                        isLastCol = ((index-wraps.length) % colspan == 0);
                    }
                    // const isLastCol = ((idx-wraps.length) % colspan == 0);
                    const span = forceSpan > 0 ? forceSpan : defaultSpan * colspanOfField;
                    if (isWrap || isLastCol || isAutoWrap) {
                        cols = [{field, span}];
                        rows.push(cols);
                    } else {
                        cols.push({field, span});
                    }
                });
                const fieldSetChildren = rows.length > 0 ?
                    rows.map((cols, idx) => (
                        <Row key={idx} >
                            {cols.map(({field, span}) =>
                                <Col key={field.id} span={span}>
                                    {this.renderFormItem({form, fieldSet, field, getFieldDecorator})}
                                </Col>
                            )}
                        </Row>
                    )) :
                    fields.map(field =>
                        this.renderFormItem({form, fieldSet, field, getFieldDecorator})
                    );
                return  (
                    formModel.isHideFieldSets ? (
                        <div key={fieldSet.id} header={fieldSet.label}>
                            { fieldSetChildren }
                        </div>
                    ) : (
                        <Panel key={fieldSet.id} header={fieldSet.label} showArrow={showArrow}>
                            { fieldSetChildren }
                        </Panel>
                    )
                );
            }
        }
        const children = fields.map(field => {
            return this.renderFormItem({form, fieldSet, field, getFieldDecorator})
            // console.log(field.visible);
            // console.log('!field.visible',!field.visible);
            // return !field.visible ? 
            //             null : this.renderFormItem({form, fieldSet, field, getFieldDecorator})
            // if(field.visible){
            //     return this.renderFormItem({form, fieldSet, field, getFieldDecorator})
            // }
            // return null;
        });
        return  (
            formModel.isHideFieldSets ? (
                <div key={fieldSet.id} header={fieldSet.label}>
                    { children }
                </div>
            ) : (
                <Panel key={fieldSet.id} header={fieldSet.label} showArrow={showArrow}>
                    { children }
                </Panel>
            )
        );
    }
    handleFormReady = ({form}) => {
        const { handleFormReady=()=>{} } = this.props;
        this.form = form;
        handleFormReady({form});
    }
    render() {
        const {
            className,
            formModel={},
            renderItems:renderMoreItems=()=>{},
            bordered=true,
            accordion=false,
            handleValidate,
            emptyText='Form Model Data Not Found',
            onPanelChange,
        } = this.props;
        const renderFormChildren = ({form, formModel, getFieldDecorator}) => {
            return formModel.fieldSets.map(fieldSet =>
                this.renderFieldSet({ form, fieldSet, getFieldDecorator })
            );
        };

        return formModel.fieldSets && formModel.fieldSets.length > 0 ? (
            <FormWrap
                className={className}
                layout={this.getLayoutType(formModel)}
                onValuesChange={this.handleValuesChange}
                onFieldsChange={this.handleFieldsChange}
                onComponentDidMount={this.handleFormReady}
                handleValidate={handleValidate}
                renderItems={({form, getFieldDecorator})=>([
                    formModel.isHideFieldSets ? (
                        <div
                            key={formModel.id}
                            style={{
                                background: "white",
                                padding: "16px"
                            }}
                        >
                            { renderFormChildren({form, formModel, getFieldDecorator}) }
                        </div>
                    ) : (
                        <Collapse
                            key={formModel.id}
                            accordion={accordion}
                            bordered={bordered}
                            defaultActiveKey={formModel.fieldSets.map(fs => fs && `${fs.id}`)}
                            onChange={onPanelChange}
                        >
                            { renderFormChildren({form, formModel, getFieldDecorator}) }
                        </Collapse>
                    ),
                    renderMoreItems({form, getFieldDecorator}),
                ])}
            />
        ) : emptyText;
    }
}

export default DynamicForm;